/*
* Copyright (c) 2021 Talkweb Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <stdio.h>
#include "service_auth.h"

int32_t service_auth_tls_psk(tiot_sysdep_portfile_t *sysdep, char **psk_id, char psk[65], char *product_key, char *device_name, char *device_secret)
{
    int32_t res = RET_SUCCESS;
    char *tmp_psk_id = NULL, *auth_type = "devicename", *sign_method = "hmacsha256";
    char *psk_id_src[] = { auth_type, sign_method, product_key, device_name, SERVICE_AUTH_TIMESTAMP};
    char *psk_plain_text = NULL, *psk_plain_text_src[] = { product_key, device_name, SERVICE_AUTH_TIMESTAMP};
    uint8_t psk_hex[32] = {0};

    if (NULL == device_secret) {
        return RET_USER_INPUT_MISSING_DEVICE_SECRET;
    }

    res = service_sprintf(sysdep, &tmp_psk_id, "%s|%s|%s&%s|%s", psk_id_src, sizeof(psk_id_src)/sizeof(char *));
    if (res < RET_SUCCESS) {
        return res;
    }

    res = service_sprintf(sysdep, &psk_plain_text, "id%s&%stimestamp%s", psk_plain_text_src, sizeof(psk_plain_text_src)/sizeof(char *));
    if (res < RET_SUCCESS) {
        sysdep->service_sysdep_free(tmp_psk_id);
        return res;
    }

    service_hmac_sha256((const uint8_t *)psk_plain_text, (uint32_t)strlen(psk_plain_text), (const uint8_t *)device_secret, (uint32_t)strlen(device_secret), psk_hex);
    service_hex2str(psk_hex, 32, psk, 0);

    *psk_id = tmp_psk_id;
    sysdep->service_sysdep_free(psk_plain_text);

    return res;
}

int32_t service_auth_mqtt_username(tiot_sysdep_portfile_t *sysdep, char **dest, char *product_key, char *device_name)
{
    char *src[] = { device_name, product_key };

    return service_sprintf(sysdep, dest, "%s&%s", src, sizeof(src)/sizeof(char *));
}

int32_t service_auth_mqtt_password(tiot_sysdep_portfile_t *sysdep, char **dest, uint64_t auth_timestamp, char *product_key, char *device_name, char *device_secret, uint8_t assigned_clientid)
{
    int32_t res = 0;
    char *plain_text = NULL;
    uint8_t time_stamp[32] = {0};
    uint8_t sign[32] = {0};
    sprintf(time_stamp,"%ld",auth_timestamp);

    if(1 == assigned_clientid) {
        char *src[] = { device_name, product_key, time_stamp };
        res = service_sprintf(sysdep, &plain_text, "clientIddeviceName%sproductKey%stimestamp%s", src, sizeof(src)/sizeof(char *));
    } else {
        char *src[] = { sysdep->service_unique_identifier(), device_name, product_key, time_stamp };
        res = service_sprintf(sysdep, &plain_text, "clientId%sdeviceName%sproductKey%stimestamp%s", src, sizeof(src)/sizeof(char *));
    }

    if (res < RET_SUCCESS) {
        return res;
    }

    *dest = sysdep->service_sysdep_malloc(65);
    if (*dest == NULL) {
        sysdep->service_sysdep_free(plain_text);
        return RET_SYS_DEPEND_MALLOC_FAILED;
    }
    memset(*dest, 0, 65);

    service_hmac_sha256((const uint8_t *)plain_text, (uint32_t)strlen(plain_text), (const uint8_t *)device_secret, (uint32_t)strlen(device_secret),sign);
    service_hex2str(sign, 32, *dest, 0);

    sysdep->service_sysdep_free(plain_text);

    return 0;
}

int32_t service_auth_mqtt_clientid(tiot_sysdep_portfile_t *sysdep, char **dest, uint64_t auth_timestamp, char *product_key, char *device_name, char *secure_mode, char *extend_clientid, uint8_t assigned_clientid)
{
    uint8_t time_stamp[32] = {0};

    sprintf(time_stamp,"%ld",auth_timestamp);
    if(1 == assigned_clientid) {
        char *src[] = { SERVICE_AUTH_TIMESTAMP, SERVICE_AUTH_SDK_VERSION, secure_mode, extend_clientid};
        return service_sprintf(sysdep, dest, "|timestamp=%s,_ss=1,_v=%s,securemode=%s,signmethod=hmacsha256,ext=3,%s|", src, sizeof(src)/sizeof(char *));
    }
   char *src[] = { sysdep->service_unique_identifier(), SERVICE_AUTH_ENCRYPTION_TYPE, time_stamp};
   return service_sprintf(sysdep, dest, "%s|signmethod=%s,timestamp=%s|", src, sizeof(src)/sizeof(char *));
}

int32_t service_auth_http_body(tiot_sysdep_portfile_t *sysdep, char **dest, char *product_key, char *device_name, char *device_secret)
{
    int32_t res = 0;
    uint64_t auth_timestamp = 0;
    uint8_t time_stamp[32] = {0};
    sprintf(time_stamp,"%ld",auth_timestamp);
    char *sign_ele[] = { device_name, product_key, time_stamp, NULL};
    char *sign_auth[] = { product_key, device_name, time_stamp, NULL, "hmacsha256"};
    char *plain_text = NULL;
    uint8_t sign_hex[32] = {0};
    char sign_str[65] = {0};

    res = service_sprintf(sysdep, &plain_text, "deviceName%sproductKey%stimestamp%s", sign_ele, 3);
    if (res < RET_SUCCESS) {
        return res;
    }

    service_hmac_sha256((const uint8_t *)plain_text, (uint32_t)strlen(plain_text), (const uint8_t *)device_secret, (uint32_t)strlen(device_secret), sign_hex);
    service_hex2str(sign_hex, 32, sign_str, 0);

    sysdep->service_sysdep_free(plain_text);
    sign_auth[3] = sign_str;
    res = service_sprintf(sysdep,
                       dest,
                       "{\"productKey\":\"%s\",\"deviceName\":\"%s\",\"timestamp\":\"%s\",\"sign\":\"%s\",\"signMethod\":\"%s\"}",
                       sign_auth,
                       sizeof(sign_auth)/sizeof(char *));

    return res;
}

